/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Validated Data Container Collection Class
 *      Provides a custom collection class for storing ValidatedDataContainer instances.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.IO;
using Adaptive.Foundation;

namespace Adaptive.Foundation.IO
{
    /// <summary>
    /// Provides a custom collection class for storing <see cref="ValidatedDataContainer"/> instances.
    /// </summary>
    public class ValidatedDataContainerCollection : GenericCollectionBase<ValidatedDataContainer>
    {
        /*--------------------------------------------------------------------------------
         * Private Constants Declarations
         *------------------------------------------------------------------------------*/
        #region Private Constants Declarations
        /// <summary>
        /// Default 64K data block size.
        /// </summary>
        private const int DEF_BLOCK_SIZE = 65536;
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// Size of data blocks when creating data blocks from raw data.
        /// </summary>
        private int _dataBlockSize = DEF_BLOCK_SIZE;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// </remarks>
        public ValidatedDataContainerCollection()
            : base()
        {
        }
        /// <summary>
        /// Initializes a new instance of the class for the content in the specified
        /// source stream.
        /// </summary>
        /// <param name="sourceData">
        /// An open <see cref="Stream"/> containing properly formatted data blocks.
        /// </param>
        public ValidatedDataContainerCollection(Stream sourceData)
        {
            LoadFromStream(sourceData);
        }
        /// <summary>
        /// Initializes a new instance of the class for the content in the specified
        /// source stream.
        /// </summary>
        /// <param name="reader">
        /// An open <see cref="BinaryReader"/> used to read a stream containing properly formatted data blocks.
        /// </param>
        public ValidatedDataContainerCollection(BinaryReader reader)
        {
            LoadFromStream(reader);
        }
        /// <summary>
        /// Initializes a new instance of the class for the content in the specified
        /// source stream.
        /// </summary>
        /// <param name="sourceData">
        /// An open <see cref="Stream"/> containing properly formatted data blocks.
        /// </param>
        /// <param name="dataBlockSize">
        /// The size of the data blocks, in bytes.
        /// </param>
        public ValidatedDataContainerCollection(Stream sourceData, int dataBlockSize)
        {
            _dataBlockSize = dataBlockSize;
            CreateFromStream(sourceData);
        }
        /// <summary>
        /// Initializes a new instance of the class for the content in the specified
        /// source stream.
        /// </summary>
        /// <param name="reader">
        /// An open <see cref="BinaryReader"/> used to read a stream containing properly formatted data blocks.
        /// </param>
        /// <param name="dataBlockSize">
        /// The size of the data blocks, in bytes.
        /// </param>
        public ValidatedDataContainerCollection(BinaryReader reader, int dataBlockSize)
        {
            _dataBlockSize = dataBlockSize;
            CreateFromStream(reader);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets or sets the size of the data blocks to create when loading 
        /// raw data into the AI data block format.
        /// </summary>
        /// <value>
        /// The size of the data blocks, in bytes.
        /// </value>
        public int DataBlockSize
        {
            get { return _dataBlockSize; }
            set
            {
                _dataBlockSize = value;
            }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods / Event Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods / Event Methods
        /// <summary>
        /// Gets the unique reference key value used to reference the instance once stored
        /// in the collection instance.
        /// </summary>
        /// <param name="itemToGetKeyFor">
        /// The object being appended to the collection instance.
        /// </param>
        /// <returns>
        /// A reference key value.
        /// </returns>
        protected override string GetKeyForObject(ValidatedDataContainer itemToGetKeyFor)
        {
            if (itemToGetKeyFor != null)
                return itemToGetKeyFor.ID;
            else
                return string.Empty;
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Loads the content of a stream in the proper format.
        /// </summary>
        /// <param name="sourceData">
        /// An open <see cref="Stream"/> instance used to read the formatted
        /// data blocks.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Occurs if the <i>sourceData</i> parameter is null.
        /// </exception>
        /// <exception cref="IOException">
        /// May occur if there is an I/O failure.
        /// </exception>
        /// <exception cref="AiCrcFailedException">
        /// Occurs when the CRC data comparison fails.
        /// </exception>
        /// <exception cref="AiHashCodeFailedException">
        /// Occurs when the hash code comparisong fails.
        /// </exception>
        public void LoadFromStream(Stream sourceData)
        {
            BinaryReader reader = null;                 //Data reader.

            if (sourceData == null)
                throw new ArgumentNullException();
            reader = new BinaryReader(sourceData);
            LoadFromStream(reader);
            reader = null;
        }
        /// <summary>
        /// Loads the content of a stream in the proper format.
        /// </summary>
        /// <param name="reader">
        /// An open <see cref="BinaryReader"/> instance used to read the <see cref="Stream"/> 
        /// containing the formatted data blocks.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Occurs if the <i>sourceData</i> parameter is null.
        /// </exception>
        /// <exception cref="IOException">
        /// May occur if there is an I/O failure.
        /// </exception>
        /// <exception cref="AiCrcFailedException">
        /// Occurs when the CRC data comparison fails.
        /// </exception>
        /// <exception cref="AiHashCodeFailedException">
        /// Occurs when the hash code comparisong fails.
        /// </exception>
        public void LoadFromStream(BinaryReader reader)
        {
            ValidatedDataContainer newItem = null;          //New item for collection.

            if (reader == null)
                throw new ArgumentNullException();

            //Clear current contents and read until the position reaches the end.
            Clear();

            while (reader.BaseStream.Position < reader.BaseStream.Length)
            {
                newItem = new ValidatedDataContainer(reader);
                newItem.Index = Count;
                Add(newItem);
            }
        }
        /// <summary>
        /// Reads the raw content of an open stream and creates the related data blocks.
        /// </summary>
        /// <param name="sourceData">
        /// An open <see cref="Stream"/> containing the content to be translated.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Occurs if the <i>reader</i> parameter is <b>null</b>.
        /// </exception>
        public void CreateFromStream(Stream sourceData)
        {
            BinaryReader reader = null;

            if (sourceData == null)
                throw new ArgumentNullException();
            reader = new BinaryReader(sourceData);
            CreateFromStream(reader);
            reader = null;
        }
        /// <summary>
        /// Reads the raw content of an open stream and creates the related data blocks.
        /// </summary>
        /// <param name="reader">
        /// A <see cref="BinaryReader"/> used to read the content of the open stream.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Occurs if the <i>reader</i> parameter is <b>null</b>.
        /// </exception>
        public void CreateFromStream(BinaryReader reader)
        {
            ValidatedDataContainer newItem = null;
            byte[] rawData = null;

            if (reader == null)
                throw new ArgumentNullException();

            while (reader.BaseStream.Position < reader.BaseStream.Length)
            {
                //Read content.
                rawData = reader.ReadBytes(_dataBlockSize);
                if ((rawData != null) && (rawData.Length > 0))
                {
                    newItem = new ValidatedDataContainer(rawData);
                    newItem.Index = Count;
                    Add(newItem);
                }
            }
        }
        /// <summary>
        /// Saves the current content to the specified stream.
        /// </summary>
        /// <param name="sourceStream">
        /// A <see cref="Stream"/> to which the content is to be written.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Occurs when the <i>sourceStream</i> parameter is <b>null</b>.
        /// </exception>
        public void SaveToStream(Stream sourceStream)
        {
            BinaryWriter writer = null;

            if (sourceStream == null)
                throw new ArgumentNullException();

            writer = new BinaryWriter(sourceStream);
            SaveToStream(writer);
            writer = null;
        }
        /// <summary>
        /// Saves the current content to the specified stream.
        /// </summary>
        /// <param name="writer">
        /// A <see cref="BinaryWriter"/> used to write content to an open stream.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Occurs when the <i>writer</i> parameter is <b>null</b>.
        /// </exception>
        public void SaveToStream(BinaryWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException();

            foreach (ValidatedDataContainer container in this)
                container.WriteToStream(writer);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Event Handlers
         *------------------------------------------------------------------------------*/
        #region Private Event Handlers
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Private Methods / Functions
        #endregion

    }
}
